<?php

class Kd_Loader {

    static private $_scopes = array();
    static private $_includePaths = array();
    static private $_singletons = array();
    static private $_foundClasses = array();

    static public function addScope() {
        $args = func_get_args();
        if(is_array($args[0])){
            $args = $args[0];
        }
        self::$_scopes = array_merge($args, self::$_scopes);
    }

    static public function getScopes() {
        return self::$_scopes;
    }

    static public function addIncludePath() {
        $arr = func_get_args();
        if (!empty(self::$_includePaths)) {
            $oldIncludePath = implode(PATH_SEPARATOR, self::$_includePaths);
            self::$_includePaths = array_merge($arr, self::$_includePaths);
            $newIncludePath = implode(PATH_SEPARATOR, self::$_includePaths);
            ini_set('include_path', str_replace($oldIncludePath, $newIncludePath, ini_get('include_path')));
        } else {
            self::$_includePaths = $arr;
            $ps = implode(PATH_SEPARATOR, $arr);
            ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . $ps);
        }
    }

    static public function getIncludePaths() {
        return self::$_includePaths;
    }

    static public function getSingleton($className) {
        if (!isset(self::$_singletons[$className])) {
            self::$_singletons[$className] = new $className();
        }

        return self::$_singletons[$className];
    }

    static public function loadSingleton($className) {
        if (!isset(self::$_singletons[$className])) {
            self::$_singletons[$className] = self::loadInstance($className);
        }

        return self::$_singletons[$className];
    }

    static public function loadInstance($className) {
        $class = self::loadClass($className);
        if (empty($class)) {
            throw new Exception('Not found class [' . $className . ']');
        }

        $class = self::loadClass($className);
        return new $class();
    }

    static public function loadClass($className) {
        if (self::isIncludeScope($className)) {
            return $className;
        }

        if (isset(self::$_foundClasses[$className])) {
            return self::$_foundClasses[$className];
        }

        if (!isset(self::$_foundClasses[$className])) {
            $subPath = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $className))) . '.php';
            foreach (self::$_scopes as $scope) {
                foreach (self::$_includePaths as $path) {
                    if (file_exists($path . $scope . DIRECTORY_SEPARATOR . $subPath)) {
                        self::$_foundClasses[$className] = $scope . '_' . $className;
                        return $scope . '_' . $className; 
                    }
                }
            }
        }

        return NULL;
    }

    static private function isIncludeScope($className) {
        $arr = explode('_', $className);
        return in_array($arr[0], self::$_scopes);
    }
}